#include "../include/hash.h"

inline unsigned long hash_op_def(hash_key_t key, unsigned long n) {
        return key % n;
}

inline void hash_set_space(hash_head_t * head, void * buf, unsigned long size) {
	int i = 0;
	head->phash = (hash_t **) buf;
	head->n = size / sizeof(hash_t *);
	for (i = 0; i < head->n; ++i) {
		*(head->phash+i) = NULL;
	}
}

inline hash_op hash_set_function( hash_head_t * head, const hash_op pfunc) {
	hash_op old;
	old = head->op;
	head->op = pfunc;
	return old;
}

inline bool hash_is_empty(const hash_head_t * head) {
	if (head->phash == NULL && head->n == 0) {
		return true;
	}
	return false;
}

inline bool hash_is_exist(const hash_head_t * head, const hash_t * unit) {
        unsigned long i;
        hash_t * p;
        if (hash_is_empty(head)) {
                return false;
        }
        i = (head->op)(unit->key, head->n);
        p = *(head->phash+i);
        while ( p != NULL ){
                if (p == unit) {
                        return true;
                }
                p = p->next;
        }
        return false;
}

inline void hash_empty(hash_head_t * head) {
	head->phash = NULL;
	head->n = 0;
	head->op = HASH_OP_DEF;
}

inline void hash_set_key(hash_t * unit, hash_key_t key) {
	unit->key = key;	
}

inline hash_key_t hash_get_key(const hash_t * unit) {
	return unit->key;
}

inline void hash_add(hash_head_t * head, hash_t * unit) {
	unsigned long index;
	index = (head->op)(unit->key, head->n);		
		
#ifdef SAFE_TYPE
	if (hash_is_exist(head, unit)) {
		return;
	}
#endif
	if (*(head->phash+index) == NULL) {
		*(head->phash+index) = unit;	
		unit->next = NULL;
	}
	else {
		unit->next = *(head->phash+index);
		*(head->phash+index) = unit; 
	}
}

inline void hash_del(hash_head_t * head, hash_t * unit) {
	unsigned long index;
	hash_t * p, *q;
	index = (head->op)(unit->key, head->n);
	if (*(head->phash+index) == NULL) {
		return ;
	}	
	if (*(head->phash+index) == unit) {
		*(head->phash+index) = (*(head->phash+index))->next;
		return ;
	}
	
	p = *(head->phash+index);
	q = (*(head->phash+index))->next;
	while ( q != NULL ) {
		if ( q == unit ) {
			p->next = q->next;	
			break;
		}										
		p = q;
		q = q->next;
	}
}

inline void hash_del_by_key(hash_head_t * head, hash_key_t key) {
	unsigned long index;
        hash_t * p, *q;
        index = (head->op)(key, head->n);
	*(head->phash+index) = NULL;
}

inline unsigned long hash_find_count(hash_head_t * head, hash_key_t key) {
	unsigned long count = 0;
	unsigned long index; 
	hash_t * p;
	index = (head->op)(key, head->n);
	p = *(head->phash+index);
	while ( p != NULL) {
		++count;
		p = p->next;
	}
	return count;
}

inline const hash_t * hash_find(hash_head_t * head, hash_key_t key, unsigned long index) {
	unsigned long i;
	i = (head->op)(key, head->n);
	hash_t *p = *(head->phash+i);
	while (p != NULL &&  index-- != 0) {
		p = p->next;		
	}		
	return p;
}
